<template>
  <div class="edit-add-form">
    <a-form @submit="handleSubmit" :form="form">
      <!-- 模型名称 -->
      <a-form-item label="模型名称" :labelCol="formItemLayout.shortLabel" :wrapperCol="formItemLayout.shortWrapper">
        <a-input
          v-decorator="['modelName', { rules: [{ required: true, message: '请输入模型名称' }] }]"
          placeholder="请输入模型名称"
          :disabled="isEdit"
        />
      </a-form-item>

      <!-- 模型编号 -->
      <a-form-item label="算法/库/框架：" :labelCol="formItemLayout.longLabel" :wrapperCol="formItemLayout.longWrapper">
        <a-select
          v-decorator="['aiEngine', { rules: [{ required: true, message: '请选择算法/库/框架' }] }]"
          placeholder="请选择算法/库/框架"
          @change="handleAiEngineChange"
          style="width: 50%"
        >
          <a-select-option v-for="item in aiEngineList" :key="item.value" :value="item.value">
            {{ item.label }}
          </a-select-option>
        </a-select>
        <a-select
          v-decorator="['aiEngineVersion', { rules: [{ required: true, message: '请选择版本' }] }]"
          placeholder="请选择版本"
          style="width: 50%"
        >
          <a-select-option v-for="item in aiEngineVersionList" :key="item.value" :value="item.value">
            {{ item.label }}
          </a-select-option>
        </a-select>
      </a-form-item>
      <a-form-item
        label="模型文件"
        :labelCol="formItemLayout.longLabel"
        :wrapperCol="formItemLayout.longWrapper"
        required
      >
        <a-tooltip title="序列化的模型文件，一般为pickle格式，支持任意格式（自定义算法/库/框架支持上传多个模型文件）">
          <a-upload
            v-decorator="['pickleFiles', { rules: [{ required: true, message: '请上传模型文件' }] }]"
            style="display: inline-block"
            name="file"
            :multiple="false"
            :fileList="localFiles.pickleFiles ? [localFiles.pickleFiles] : []"
            @change="(info) => handleFileChange(info, 'pickleFiles')"
            :before-upload="(file) => beforeUpload(file, 'pickleFiles')"
          >
            <a-button> <a-icon type="upload" /> 上传 </a-button>
          </a-upload>
        </a-tooltip>
      </a-form-item>
      <a-form-item
        label="特征列表"
        :labelCol="formItemLayout.longLabel"
        :wrapperCol="formItemLayout.longWrapper"
        required
      >
        <a-space class="upload-space">
          <a-tooltip
            title="仅支持上传.csv文件，且上传特征字段顺序与建模时候输入特征字段顺序一致，否则导致预测结果不一致"
          >
            <a-upload
              name="file"
              :multiple="false"
              v-decorator="['templateFile', { rules: [{ required: true, message: '请上传特征列表文件' }] }]"
              :fileList="localFiles.templateFile ? [localFiles.templateFile] : []"
              @change="(info) => handleFileChange(info, 'templateFile')"
              :before-upload="(file) => beforeUpload(file, 'templateFile')"
            >
              <a-button> <a-icon type="upload" /> 上传 </a-button>
            </a-upload>
          </a-tooltip>
          <a-button
            type="link"
            @click="downloadTemplate('pythonInputTemplate', 'pythonInputTemplate.csv')"
            style="display: inline-block"
            >模版下载</a-button
          >
        </a-space>
      </a-form-item>
      <!-- 运行环境 -->
      <a-form-item label="运行环境" :labelCol="formItemLayout.longLabel" :wrapperCol="formItemLayout.longWrapper">
        <a-button @click="handleViewPythonModelVersion">查看</a-button>
      </a-form-item>

      <!-- 输出设置 -->
      <a-form-item label="输出设置" :labelCol="formItemLayout.longLabel" :wrapperCol="formItemLayout.longWrapper">
        <a-select
          v-decorator="['modelAlgorithm', { rules: [{ required: true, message: '请选择输出类型' }] }]"
          placeholder=" 请选择输出类型"
          @change="handleOutputSetChange"
        >
          <a-select-option v-for="item in outputSetList" :key="item.value" :value="item.value">
            {{ item.label }}
          </a-select-option>
        </a-select>
        <a-input-number
          v-decorator="['moreOutput', { rules: [{ required: true, message: '请输入分类数' }] }]"
          placeholder="请输入分类数"
          v-if="isShowOutputSet"
        />
      </a-form-item>

      <!-- 自定义输出变量 -->
      <a-form-item
        label="输出变量"
        :labelCol="formItemLayout.longLabel"
        :wrapperCol="formItemLayout.longWrapper"
        required
      >
        <EditTable
          v-decorator="[
            'outputs',
            {
              rules: [
                {
                  required: true,
                  validator: (rule, value, callback) => {
                    if (value.length === 0) {
                      callback('请至少添加一条输出变量')
                    } else {
                      let isExist = false
                      value.forEach((item) => {
                        if (!item.datatype || !item.datatype || !item.description) {
                          isExist = true
                        }
                      })
                      if (isExist) {
                        callback('请填写完整输出变量')
                        return
                      }
                      callback()
                    }
                  },
                },
              ],
              initialValue: outputs,
            },
          ]"
        />
        <a-space v-if="isShowCustomOutput" class="upload-space">
          <a-tooltip
            title="仅支持上传.csv文件，且上传特征字段顺序与建模时候输入特征字段顺序一致，否则导致预测结果不一致"
          >
            <a-upload
              name="file"
              :multiple="false"
              :fileList="[]"
              @change="handleBatchSettingsChange"
              :before-upload="(file) => beforeUpload(file, 'templateFile')"
            >
              <a-button> <a-icon type="upload" /> 批量设置 </a-button>
            </a-upload>
          </a-tooltip>
          <a-button
            type="link"
            @click="downloadTemplate('pythonOutputTemplate', 'pythonOutputTemplate.csv')"
            style="display: inline-block"
            >模版下载</a-button
          >
        </a-space>
      </a-form-item>

      <a-form-item label="预测脚本" :labelCol="formItemLayout.fullLabel" :wrapperCol="formItemLayout.fullWrapper">
        <code-mirror-input
          v-decorator="[
            'pythonCode',
            {
              initialValue: modelCode,
              rules: [{ required: true, message: '请输入代码内容！' }],
            },
          ]"
          :mode="'python'"
          :readonly="false"
        />
      </a-form-item>
      <!-- 提交按钮 -->
      <a-form-item :wrapperCol="formItemLayout.submitWrapper" style="text-align: center">
        <a-space>
          <a-button style="margin-left: 8px" @click="handleCancel"> 取消 </a-button>
          <a-button @click="handleRunTest(false)" :loading="submitLoading">试运行</a-button>
          <a-button htmlType="submit" type="primary" :loading="submitLoading"> 部署 </a-button>
        </a-space>
      </a-form-item>
    </a-form>
    <!-- 运行环境 -->
    <a-modal title="运行环境" :visible.sync="visible" width="40%" :footer="null" @cancel="visible = false">
      <a-textarea readonly :style="{ height: '400px' }" :value="runtimeEnvironment" />
    </a-modal>
    <!-- 试运行结果弹窗 -->
    <a-modal title="试运行结果" :visible.sync="testVisible" width="60%" @cancel="testVisible = false">
      <TestResult :testResult="testResult" />
      <template slot="footer">
        <a-button @click="testVisible = false">取消</a-button>
        <a-button
          type="primary"
          @click="handleRunTest(true)"
          :disabled="!testResult.success"
          :loading="submitLoading"
          v-if="isShowDeployButton"
          >确认部署</a-button
        >
      </template>
    </a-modal>
  </div>
</template>

<script>
import {
  queryAiEngine,
  getPythonOutputSet,
  downloadPythonModelTemplate,
  queryRequirements,
  newDeploy,
  parseTemplate,
} from '@/api/manage'
import CodeMirrorInput from './CodeMirrorFormItem.vue'
import EditTable from './EditTable.vue'
import TestResult from './TestResult.vue'

export default {
  name: 'EditAndAddForm',
  components: {
    CodeMirrorInput,
    EditTable,
    TestResult,
  },
  props: {
    // 是否为编辑模式
    isEdit: {
      type: Boolean,
      default: false,
    },
    // 编辑时的初始数据
    initialData: {
      type: Object,
      default: () => ({}),
    },
  },
  data() {
    return {
      form: this.$form.createForm(this),
      submitLoading: false,
      uploadAction: '/api/model/upload', // 文件上传接口
      uploadHeaders: {
        authorization: 'Bearer ' + this.$store.getters.token,
      },
      // 新增：本地文件存储
      localFiles: {
        templateFile: null,
        pickleFiles: null,
      },
      outputSetList: [],
      AiEngineData: null,
      modelCode: '',
      runtimeEnvironment: '',
      visible: false,
      outputData: [],
      aiEngineVersionList: [],
      outputs: [],
      // 表单布局常量配置
      formItemLayout: {
        // 短标签布局（如：模型名称）
        shortLabel: { lg: { span: 4 }, sm: { span: 4 } },
        shortWrapper: { lg: { span: 10 }, sm: { span: 17 } },
        // 长标签布局（如：算法/库/框架）
        longLabel: { lg: { span: 4 }, sm: { span: 4 } },
        longWrapper: { lg: { span: 10 }, sm: { span: 17 } },
        // 全宽布局（如：预测脚本）
        fullLabel: { lg: { span: 4 }, sm: { span: 4 } },
        fullWrapper: { lg: { span: 17 }, sm: { span: 24 } },
        // 提交按钮布局
        submitWrapper: { span: 24 },
      },
      testVisible: false,
      testResult: null,
      isShowDeployButton: false,
      isShowOutputSet: false,
      isShowCustomOutput: false,
    }
  },
  created() {
    this.initFormData()
  },
  mounted() {},
  computed: {
    aiEngineList() {
      if (!this.AiEngineData) {
        return []
      }
      console.log(this.AiEngineData)
      return Object.keys(this.AiEngineData).map((key) => ({
        label: this.AiEngineData[key].nameCn,
        value: key,
      }))
    },
  },
  methods: {
    initEditData() {
      // 如果是编辑模式，填充表单数据
      if (this.isEdit && this.initialData) {
        this.$nextTick(() => {
          console.log('---mounted---', this.initialData)
          const {
            modelName,
            aiEngine,
            modelAlgorithm,
            aiEngineVersion,
            moreOutput,
            parameters: { outputs },
          } = this.initialData
          if (modelAlgorithm === 'classifier_more') {
            this.isShowOutputSet = true
          } else if (modelAlgorithm === 'custom') {
            this.isShowCustomOutput = true
          }
          this.outputs = outputs.map((item) => ({ ...item, isInitial: true }))
          this.form.setFieldsValue({
            modelName,
            aiEngine,
            modelAlgorithm,
            aiEngineVersion,
            moreOutput,
            outputs: outputs.map((item) => ({ ...item, isInitial: true })),
            pythonCode: this.AiEngineData[aiEngine].pythonCode,
          })
        })
      }
    },
    // 初始化表单数据
    initFormData() {
      // 修复：调用函数而不是传递函数引用
      Promise.all([queryAiEngine(), getPythonOutputSet()])
        .then((responses) => {
          // 检查每个响应的状态
          const [aiEngineRes, outputSetRes] = responses

          if (aiEngineRes.code === 200) {
            this.AiEngineData = aiEngineRes.data
          }

          if (outputSetRes.code === 200) {
            this.outputSetList = outputSetRes.data.map((item) => ({
              label: item.nameCn,
              value: item.name,
              paramList: item.paramList,
            }))
          }

          // 在数据加载完成后初始化编辑数据
          this.initEditData()
        })
        .catch((err) => {
          console.error('初始化数据失败:', err)
          this.$message.error('初始化数据失败，请重试')
        })
    },
    /**
     * 算法/库/框架 改变时
     * @param val 算法/库/框架
     */
    handleAiEngineChange(val) {
      console.log('val--', val)
      const version = this.AiEngineData[val].version
      this.modelCode = this.AiEngineData[val].pythonCode
      this.aiEngineVersionList = [
        {
          label: version,
          value: version,
        },
      ]
      this.form.setFieldsValue({
        aiEngineVersion: version,
        aiEngine: val,
        pythonCode: this.modelCode,
      })
    },
    downloadTemplate(templateName, fileName) {
      downloadPythonModelTemplate(templateName, fileName)
        .then((result) => {
          console.log('下载成功:', result)
          this.$message.success('下载成功')
        })
        .catch((error) => {
          console.error('下载失败:', error)
          this.$message.error('下载失败')
        })
    },
    handleViewPythonModelVersion() {
      queryRequirements().then((res) => {
        if (res.code === 200) {
          this.runtimeEnvironment = res.data
          this.visible = true
        }
      })
    },
    handleOutputSetChange(val) {
      this.outputData = this.outputSetList.find((item) => item.value === val).paramList
      this.isShowCustomOutput = false
      this.isShowOutputSet = false
      if (val === 'classifier_more') {
        this.isShowOutputSet = true
      } else if (val === 'custom') {
        this.isShowCustomOutput = true
      }
      this.form.setFieldsValue({
        outputs: this.outputData,
        moreOutput: '',
      })
    },
    handleRunTest(isDeploy = false) {
      this.form.validateFields((err, values) => {
        console.log('values--', err, values)
        if (!err) {
          this.submitLoading = true
          const { modelName, aiEngine, modelAlgorithm, aiEngineVersion, outputs, pythonCode, moreOutput } = values
          const {
            templateFile: { originFileObj: templateFile },
            pickleFiles: { originFileObj: pickleFiles },
          } = this.localFiles
          const params = {
            modelName,
            modelType: aiEngine,
            modelVersion: aiEngineVersion,
            outputs: JSON.stringify(
              outputs.map((item) => ({
                name: item.name,
                datatype: item.datatype,
                description: item.description,
              }))
            ),
            outputSet: modelAlgorithm,
            ifTest: !isDeploy,
            pythonCode,
            templateFile,
            pickleFiles,
          }
          if (modelAlgorithm === 'classifier_more') {
            params.moreOutput = moreOutput
          }
          const formData = new FormData()
          Object.keys(params).forEach((key) => {
            formData.append(key, params[key])
          })
          newDeploy(formData).then((res) => {
            this.submitLoading = false
            this.testResult = res
            this.testVisible = true
            this.isShowDeployButton = res.code === 200
            // 如果部署成功,更新列表数据
            if (res.code === 200 && isDeploy) {
              this.$message.success('部署成功')
              this.$emit('updateList')
            }
          })
        }
      })
    },
    // 表单提交处理
    handleSubmit(e) {
      e.preventDefault()
      this.handleRunTest(false)
    },

    // 取消操作
    handleCancel() {
      this.$emit('cancel')
      this.form.resetFields()
    },
    handleBatchSettingsChange(info) {
      const { file } = info
      const formData = new FormData()
      formData.append('uploadFiles', file)
      formData.append('templateType', 'pythonTemplateoutput')
      parseTemplate(formData).then((res) => {
        if (res.code === 200) {
          this.form.setFieldsValue({
            outputs: res.data,
          })
          this.$message.success('批量设置成功')
        }
      })
    },
    // 文件上传前验证
    beforeUpload(file, fileType) {
      // 根据文件类型进行不同的验证
      if (fileType === 'templateFile') {
        const isCSV = file.name.toLowerCase().endsWith('.csv')
        if (!isCSV) {
          this.$message.error('模板文件只支持 .csv 格式的文件')
          return false
        }
      } else if (fileType === 'pickleFiles') {
        const isValidType = ['pkl', 'joblib', 'h5', 'pb'].some((ext) => file.name.toLowerCase().endsWith(`.${ext}`))
        if (!isValidType) {
          this.$message.error('模型文件只支持 .pkl, .joblib, .h5, .pb 格式')
          return false
        }
      }

      const isLt100M = file.size / 1024 / 1024 < 100
      if (!isLt100M) {
        this.$message.error('文件大小不能超过100MB')
        return false
      }

      // 返回 false 阻止自动上传
      return false
    },

    // 文件上传状态变化
    handleFileChange(info, fileType) {
      const { file } = info

      if (file.status !== 'removed') {
        // 创建文件对象用于显示
        const fileObj = {
          uid: file.uid,
          name: file.name,
          status: 'done',
          size: file.size,
          type: file.type,
          originFileObj: file, // 保存原始文件对象
        }

        // 保存到本地文件存储
        this.localFiles[fileType] = fileObj
        this.$message.success(`${file.name} 文件选择成功`)
      } else {
        // 文件被移除
        this.localFiles[fileType] = null
        this.$message.info('文件已移除')
      }
    },

    // 文件列表格式化
    normFile(e) {
      if (Array.isArray(e)) {
        return e
      }
      return e && e.fileList
    },

    // 上传文件到服务器
    async uploadFilesToServer() {
      const uploadPromises = []

      // 上传模型文件
      if (this.localFiles.templateFile && this.localFiles.templateFile.originFileObj) {
        const formData = new FormData()
        formData.append('file', this.localFiles.templateFile.originFileObj)

        const uploadPromise = this.$http.post(this.uploadAction, formData, {
          headers: {
            ...this.uploadHeaders,
            'Content-Type': 'multipart/form-data',
          },
        })
        uploadPromises.push(uploadPromise)
      }

      // 上传特征列表文件
      if (this.localFiles.pickleFiles && this.localFiles.pickleFiles.originFileObj) {
        const formData = new FormData()
        formData.append('file', this.localFiles.pickleFiles.originFileObj)

        const uploadPromise = this.$http.post(this.uploadAction, formData, {
          headers: {
            ...this.uploadHeaders,
            'Content-Type': 'multipart/form-data',
          },
        })
        uploadPromises.push(uploadPromise)
      }

      try {
        const results = await Promise.all(uploadPromises)
        return results
      } catch (error) {
        console.error('文件上传失败:', error)
        this.$message.error('文件上传失败，请重试')
        throw error
      }
    },
    // 验证JSON格式
    validateJSON(e) {
      const value = e.target.value.trim()
      if (value) {
        try {
          JSON.parse(value)
        } catch (error) {
          this.$message.error('配置参数格式错误，请输入有效的JSON格式')
        }
      }
    },
  },
}
</script>

<style lang="less" scoped>
.edit-add-form {
  .upload-tip {
    color: #999;
    font-size: 12px;
    margin-top: 8px;
  }

  .ant-form-item {
    margin-bottom: 24px;
  }

  .ant-btn {
    min-width: 80px;
  }
}

.upload-space {
  align-items: flex-start;
}
</style>
